<?php
/**
 * zen_analizador_cartucho.php
 * @author Juan Belon
 * @access public
 * @copyright LGPL, GPL
 * @package zenphp_generador
 * @version 0.1.1
 * @uses zenphp FrameWork
 * @link http://csl2-zenphp.forja.rediris.es
 * @link http://www.zenphp.es
 * @link https://forja.rediris.es/projects/csl2-zenphp/
 * @magic Clase que analiza un XML de un cartucho para construir sus items
 */
// +----------------------------------------------------------------------
// | zenphp.es
// +----------------------------------------------------------------------
class zen_analizador_cartucho {
	/**
	* La ventana principal asociada al analizador
	* @var zen_ventana_principal
	*/
	var $ventana_principal;
	/**
	 * Ruta del cartucho actual
	 *
	 * @var str
	 */
	var $ruta = "";
	/**
	* Array que guarda la configuración de las aplicaciones
	* @var array
	*/
	var $aplicaciones = array();
	/**
	* Constructor
	* @param zen_ventana_principal
	* @return zen_analizador_cartucho
	*/
	function zen_analizador_cartucho(&$ventana_principal){
		$this->ventana_principal =& $ventana_principal;
	}

	/**
	* Recorre $nodos construyendo cada uno de sus items
	* @param object $nodos
	*/
	function leer_nodos_cartucho(&$nodos) {
    foreach ($nodos as $nodo) {
      if (ZF_GTK_MODO_DEBUG) print_r($nodo);
      if ($nodo->nodeType != 1){
        if (ZF_GTK_MODO_DEBUG) echo 'Nodo: "'.$nodo->nodeName.'"';
        continue;
      }
      $ret = $this->construirItems($nodo);
      if (!$ret) return false; //Ha ocurrido algún fallo
    }
    return true; //En caso contrario, todo OK
	}
	/**
	 * Construye el modelo de configuración para generar las aplicaciones
	 *
	 * @param domnode $nodo
	 * @param str $tipo
	 * @param str $aplicacion_activa
	 * @param str $modelo_activo
	 * @return bool
	 */
	function construirItems(&$nodo, $tipo = null,$aplicacion_activa='',$modelo_activo="") {
		static $fab;//Ahora podemos pasar a las listas las opciones leidas y almacenadas en $this->aplicaciones
    $fab =& $this->ventana_principal->fabrica;
		if (!$tipo)
		 $tipo = $nodo->nodeName;
		//$id = $nodo->getAttribute("id");
		/*if ($tipo != "" && is_null($id)) {
			throw new Exception("Item sin id");
			return false;
		}*/
		switch ($tipo) {
			default:
			  if (ZF_GTK_MODO_DEBUG)
				 echo "Nodo no reconocido nombre:$tipo, valor:".$nodo->nodeValue;
				break;
			case '#text': break;
			case 'entrada': //Entrada del directorio de la aplicación
				$this->aplicaciones[$aplicacion_activa]['entrada'] = $nodo->nodeValue;
				$fab->anadir_filas_arbol(array(
				 'id' => Gtk::STOCK_OPEN, //imagen para la entrada
				 'tipo'  => 'Dir. entrada',
				 'nombre'=> $aplicacion_activa,
				 'contenido'=> $this->dir_ruta.str_replace("\\",DIRECTORY_SEPARATOR,$nodo->nodeValue),
				 'valor' => $nodo->nodeValue //Valor de la entrada
				));
				break;
			case 'salida': //imagen para la salida Gtk::STOCK_DIRECTORY
				$this->aplicaciones[$aplicacion_activa]['salida'] = $nodo->nodeValue;
				$fab->anadir_filas_arbol(array(
				 'id' => Gtk::STOCK_DIRECTORY, //imagen para la entrada
				 'tipo'  => 'Dir. salida',
				 'nombre'=> $aplicacion_activa,
				 'contenido'=> $this->dir_ruta.str_replace("\\",DIRECTORY_SEPARATOR,$nodo->nodeValue),
				 'valor' => $nodo->nodeValue //Valor de la entrada
				));
				break;
			case 'modelo': //Gracias a las reglas del DTD válido de un XML de cartucho no puede estar mal formado :)
				//imagen para el modelo: 
			  //luego solo puede haber un modelo activo, con el que estamos operando
				$modelo_activo = $nodo->getAttribute("nombre");
				if (Empty($modelo_activo)) $modelo_activo = $this->nombreAleatorio(6); //Nombre aleatorio en su lugar
				//Explorar los nodos del modelo:
				$this->aplicaciones[$aplicacion_activa]['modelos'][$modelo_activo] = array();
				$fab->anadir_filas_arbol(array(
				 'id'    => Gtk::STOCK_FIND_AND_REPLACE, //imagen-icono para el modelo
				 'tipo'  => 'Modelo_Datos',
				 'nombre'=> $aplicacion_activa,
				 'contenido'=> $modelo_activo." extends zen_modelo_datos",
				 'valor' => $modelo_activo //Valor de la entrada
				));
				$hijos = $nodo->childNodes;
				foreach ($hijos as $hijo){
					$this->construirItems($hijo,null,$aplicacion_activa,$modelo_activo);
				}
				break;
			case 'visualizador':
			  $v = $nodo->nodeValue;
			  if (empty($v)) $v = 'html';
				$this->aplicaciones[$aplicacion_activa]['modelos'][$modelo_activo]['visualizador'] = $v;
				$fab->anadir_filas_arbol(array(
				 'id'    => Gtk::STOCK_INDEX, //imagen-icono para el visualizador
				 'nombre'=> $aplicacion_activa,
				 'tipo'  => 'Visualizador',
				 'contenido' => $this->dir_ruta.str_replace("\\",DIRECTORY_SEPARATOR,$v),//."_$modelo_activo extends zen_html_modelo_datos",
				 'valor' => $v //Valor de la entrada
				));
				break;
			case 'ayudante':
				$a = $nodo->nodeValue;
			  if (empty($v)) {
			  	if (ZF_GTK_MODO_DEBUG) 
			  	 trigger_error("No se ha definido el ayudante correctamente para el modelo $modelo_activo de la aplicacion $aplicacion_activa",E_USER_WARNING);
			  	break;
			  }
				$this->aplicaciones[$aplicacion_activa]['modelos'][$modelo_activo]['ayudantes'][] = $a;
				$fab->anadir_filas_arbol(array(
				 'id'    => Gtk::STOCK_BOLD, //imagen-icono para el visualizador
				 'nombre'=> $aplicacion_activa,
				 'tipo'  => 'Clase Ayudante',
				 'contenido' => $v,
				 'valor' => $v //Valor de la entrada
				));
				break;
			case 'campo': 
				$tipo   = $nodo->getAttribute("tipo");
				$nombre = $nodo->nodeValue;
				if (Empty($nombre)) $nombre = $this->nombreAleatorio(6);
				$this->aplicaciones[$aplicacion_activa]['modelos'][$modelo_activo]['campos'][$nombre]['tipo'] = $tipo;
				$fab->anadir_filas_arbol(array(
				 'id'    => Gtk::STOCK_UNINDENT, //imagen-icono para el visualizador
				 'tipo'  => 'Campo de tabla',
				 'nombre'=> $aplicacion_activa,
				 'contenido' => "Tipo:".$tipo.",Modelo:".$modelo_activo,
				 'valor' => $nombre //Valor de la entrada
				));
				break;
			case 'configuracion':
				//Leer los valores de configuración
				if (ZF_GTK_MODO_DEBUG)
				 echo "\nCargando configurac.\n";
				$this->aplicaciones[$aplicacion_activa] = array();
				$hijos = $nodo->childNodes;
				foreach ($hijos as $hijo){
					$this->construirItems($hijo,null,$aplicacion_activa);
				}
				break;			
			case 'aplicacion':
				//Recorremos los nodos de la aplicacion
				$nombre = $nodo->getAttribute("nombre");
				if (empty($nombre)) $nombre = 'sin_nombre';
				if (ZF_GTK_MODO_DEBUG)
				 echo "\n\tCargando aplicac.: ".$nombre."\n";
				$hijos = $nodo->childNodes;
				foreach ($hijos as $hijo){
				  $this->construirItems($hijo,null,$nombre);
				}
				break;
			case 'previsualizacion':
				$this->ventana_principal->poner_imagen($this->dir_ruta.$nodo->nodeValue);
				break;
			case 'basedatos':
				//Leer los datos de la configuracion de la base de datos
				$nombre = $nodo->getAttribute("nombre");
				if (empty($nombre)) $nombre = "bd_".$aplicacion_activa."_".$this->nombreAleatorio(3);
				$b =& $this->aplicaciones[$aplicacion_activa]['bases_datos'][$nombre];
				$s = $nodo->getAttribute("servidor");
				$b['nombre']   = $nombre;
				$b['servidor'] = empty($s)||is_null($s)?'localhost':$s;
				$b['usuario'] = $nodo->getAttribute("usuario");
				$b['contrasena'] = $nodo->getAttribute("contrasena");
				$t = $nodo->getAttribute("tipo");
				$b['tipo'] = empty($t)||is_null($t)?'mysql':$t;
				$this->ventana_principal->anadir_bd($b);
				if (ZF_GTK_MODO_DEBUG){
				 echo "Configuracion de base de datos leida:";
				 print_r($b);
				}
				break;
					
		}
		return true; //Todo se construyó sin error...
	}
	
	/**
	* Función para crear un nombre aleatorio "único" de la $longitud especificada y devolverlo
	* @param int $longitud
	* @return str
	*/
	function nombreAleatorio($longitud=3){
		return substr(md5(uniqid(rand(), true)),0 ,intval($longitud));
	}
	
	/**
	 * Lee una imagen del fichero XML dado por $ruta del nodo <previsualizacion>ruta.jpg</previsualizacion> O <previsualizacion>ruta.gif</previsualizacion>
	 * y carga dicha imagen en un objeto GdkPixbuf pasado por referencia como $pb devolviendo el resultado
	 * @param str $ruta
	 * @param GdkPixbuf $pb
	 * @return bool
	 */
	function lee_previsualizacion_del_cartucho($ruta,&$pb){
		if (ZF_GTK_MODO_DEBUG) echo "Leyendo $ruta \n";
		
		$this->ruta = $ruta;
		$this->dir_ruta = str_replace(basename($this->ruta),"",$this->ruta);
		if (!is_readable($ruta)) {
			trigger_error("No se puede leer el XML",E_USER_WARNING);
			return false;
		}
		$lector = DOMDocument::load($ruta);
		if (!$lector || !$lector->validate()) {
			trigger_error("No se puede leer el XML o no cumple las reglas del zen_cartucho.DTD",E_USER_WARNING);
			return false;
		}
		
		$imagen = "";
		$nodos  = $lector->documentElement->childNodes;
		
		foreach ($nodos as $nodo) {
			if ($nodo->nodeType != 1) continue; //restricción del tipo de nodo
			$tipo = $nodo->nodeName;
			if (strtolower($tipo)=='previsualizacion') {//Bingo!
				$imagen = $this->dir_ruta.$nodo->nodeValue;
				//Intentar leer la imagen
				if (!is_readable($imagen)){
					//throw new Exception("No se puede leer la imagen de previsualización del cartucho: ".$imagen);
					trigger_error("No se puede leer la imagen de previsualización del cartucho: ".$imagen,E_USER_WARNING);
					return false;
				} else {
					//Hay una imagen:
					@$pb = GdkPixbuf::new_from_file($imagen)->scale_simple(32, 32, Gdk::INTERP_BILINEAR);
					return true;
				}
			}
		}
		return true; //En caso contrario, todo OK
	}
		/**
    * Procesa la carga del cartucho
    * @TODO: Terminar la función con el ejemplo del PORTAL, añadir una captura ,etc.
    */
	function cargar_cartucho($ruta){
		$this->ruta = $ruta;
		//$this->img->set_from_file($ruta);
		if (!is_readable($ruta)) return false;
		//lector XML: que lee la configuración del fichero y pone la imagen de preview,etc.
		$lector = DOMDocument::load($ruta);
		if ($this->inicio_carga_cartucho($lector)){
		 $this->cartucho_actual = $ruta; //Todo ok
		 
		}
	}
	/**
	 * Valida el objeto DOMXML y llama a la función recursiva que itera todos los nodos del 
	 * fichero para ir leyendo las definiciones del cartucho base para generar la aplicación.
	 * @param DOMDocument $xml 
	 */
	private function inicio_carga_cartucho(&$xml){
		if ($xml->validate()){
			$nodos = $xml->documentElement->childNodes;
			//Comprobar el fichero:
			return ($this->leer_nodos_cartucho($nodos));
		} else {
			throw new Exception("La validación del XML ha fallado");
		}
	}
}
?>